package top.frsf.autocodegen.service.impl;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.frsf.autocodegen.controller.dto.AutoTableExportDTO;
import top.frsf.autocodegen.entity.AutoDatasource;
import top.frsf.autocodegen.entity.AutoField;
import top.frsf.autocodegen.entity.AutoTable;
import top.frsf.autocodegen.mapper.AutoTableMapper;
import top.frsf.autocodegen.service.IAutoDatasourceService;
import top.frsf.autocodegen.service.IAutoFieldMapService;
import top.frsf.autocodegen.service.IAutoFieldService;
import top.frsf.autocodegen.service.IAutoTableService;
import top.frsf.autocodegen.utils.JdbcSessionFactoryUtil;
import top.frsf.autocodegen.utils.StringConverterUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 代码生成表(AutoTable)表服务实现类
 *
 * @author FRSF
 * @since 2024-07-29 15:36:26
 */
@Service("autoTableService")
public class AutoTableServiceImpl extends ServiceImpl<AutoTableMapper, AutoTable> implements IAutoTableService {

    @Resource
    private IAutoDatasourceService datasourceService;

    @Lazy
    @Resource
    private IAutoTableService autoTableService;

    @Resource
    private IAutoFieldService fieldService;

    @Resource
    private IAutoFieldMapService fieldMapService;
    @Autowired
    private AutoFieldMapServiceImpl autoFieldMapService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void export(AutoTableExportDTO dto) throws SQLException, ClassNotFoundException {
        AutoDatasource datasource = genJudge(dto);
        try (Connection connection = JdbcSessionFactoryUtil.getSqlSessionFactory(datasource)) {
            Integer genTableId = autoTableService.genTable(dto, connection);
            autoTableService.genField(dto, connection,genTableId);
        }
    }

    /**
     * 导出逻辑判断
     */
    private AutoDatasource genJudge(AutoTableExportDTO dto) {
        AutoDatasource datasource = datasourceService.getDatasourceById(dto.getDatasourceId());
        if (datasource == null) {
            throw new RuntimeException("数据源不存在");
        }
        Long count = this.lambdaQuery().eq(AutoTable::getTableName, dto.getTableName())
                .eq(AutoTable::getDatasourceId, dto.getDatasourceId())
                .count();
        if (count > 0) {
            throw new RuntimeException("数据表已导出");
        }
        return datasource;
    }


    @Override
    public void genField(AutoTableExportDTO dto, Connection connection,Integer genTableId) throws SQLException {
        // 查询数据表字段元数据
        PreparedStatement statement = connection.prepareStatement("select column_name, data_type,column_comment,column_key,ordinal_position from information_schema.columns " +
                "where table_schema = (select database()) and table_name = ?");
        // 字段类型映射Map
        HashMap<String, String> fieldMap = autoFieldMapService.getFieldMap();
        statement.setString(1, dto.getTableName());
        ResultSet resultSet = statement.executeQuery();
        while (resultSet.next()) {
            String key = resultSet.getString("column_key");
            AutoField build = AutoField.builder()
                    .fieldName(resultSet.getString("column_name"))
                    .fieldType(resultSet.getString("data_type"))
                    .fieldComment(resultSet.getString("column_comment"))
                    .mainKey(StringUtils.isNotBlank(key) && "PRI".equalsIgnoreCase(key) ? 1 : 0)
                    .orderNum(resultSet.getInt("ordinal_position"))
                    .caseName(StringConverterUtil.convertSnakeToSmallCamel(resultSet.getString("column_name")))
                    .tableId(genTableId)
                    .caseType(fieldMap.get(resultSet.getString("data_type")))
                    .build();
            fieldService.save(build);
        }

    }

    @Override
    public Integer genTable(AutoTableExportDTO dto, Connection connection) throws SQLException {
        PreparedStatement statement = connection.prepareStatement("select table_name, table_comment from information_schema.tables " +
                "where table_schema = (select database()) and table_name = ?");
        statement.setString(1, dto.getTableName());
        ResultSet resultSet = statement.executeQuery();
        if (resultSet.next()) {
            AutoTable build = AutoTable.builder()
                    .tableName(resultSet.getString("table_name"))
                    .className(StringConverterUtil.convertSnakeToBigCamel(resultSet.getString("table_name")))
                    .tableComment(resultSet.getString("table_comment"))
                    .datasourceId(dto.getDatasourceId())
                    .author("FRSF")
                    .email("frsf-h@foxmail.com")
                    .build();
            baseMapper.insert(build);
            return build.getId();
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTableAndField(Integer id) {
        this.removeById(id);
        List<AutoField> fieldList = fieldService.list(Wrappers.lambdaQuery(AutoField.class)
                .eq(AutoField::getTableId, id));
        List<Integer> ids = fieldList.stream()
                .map(AutoField::getId)
                .collect(Collectors.toList());
        fieldService.removeBatchByIds(ids);
    }
}

